package com.husd.framework.ddl_new;

import com.husd.framework.code.DDLColumn;
import com.husd.framework.code.DDLIndex;
import com.husd.framework.ddl.DDL;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 解析DDL语句
 * 不支持 as query_expression
 *
 * @author shengdonghu@126.com
 * @date 2024/1/19 15:39
 */
public class MySQLTable02Parser {

    private List<String> wordList; // 分好词的数据
    private WordListScanner wordListScanner;

    private CreateDefinitionTypeEnum _main_step;

    public MySQLTable02Parser(List<String> wordList) {
        this.wordList = wordList;
        this.wordListScanner = new WordListScanner(wordList);
    }

    public DDL parse() {

        _main_step = CreateDefinitionTypeEnum.tbl_name;
        DDL ddl = new DDL();
        DdlTable ddlTable = step01TableName(); // 解析表名字

        ddl.setTableName(ddlTable.getTableName());
        ddl.setTemporary(ddlTable.isTemporary());
        ddl.setIfNotExist(ddlTable.isIfNotExist());

        List<List<String>> create_definition_list = getCreateDefinitionList();

        // 这里有2部分 1部分是字段声明 1部分是索引的声明 要区分开
        List<List<String>> column_list = new ArrayList<>();
        List<List<String>> index_list = new ArrayList<>();

        boolean startIndex = false;
        for (List<String> sub : create_definition_list) {
            String first = sub.get(0);
            if (ParseUtil.isWord(first, "INDEX") ||
                    ParseUtil.isWord(first, "KEY") ||
                    ParseUtil.isWord(first, "FULLTEXT") ||
                    ParseUtil.isWord(first, "SPATIAL") ||
                    ParseUtil.isWord(first, "CONSTRAINT") ||
                    ParseUtil.isWord(first, "PRIMARY") ||
                    ParseUtil.isWord(first, "UNIQUE") ||
                    ParseUtil.isWord(first, "FOREIGN")) {
                startIndex = true;
            }
            if (!startIndex) {
                column_list.add(sub);
            } else {
                index_list.add(sub);
            }
        }

        _main_step = CreateDefinitionTypeEnum.column_definition;
        MySQLTable0201ColumnParse mySQLTable0201ColumnParse =
                new MySQLTable0201ColumnParse(column_list);
        List<DDLColumn> ddlColumnList = mySQLTable0201ColumnParse.parse();
        ddl.setColumnList(ddlColumnList);

        _main_step = CreateDefinitionTypeEnum.index_definition;
        MySQLTable0202IndexParse mySQLTable0202IndexParse =
                new MySQLTable0202IndexParse(index_list);
        List<DDLIndex> ddlIndexList = mySQLTable0202IndexParse.parse();
        ddl.setIndexList(ddlIndexList);

        _main_step = CreateDefinitionTypeEnum.table_options;
        // 解析 table_options

        //table_option: {
        //    AUTOEXTEND_SIZE [=] value
        //  | AUTO_INCREMENT [=] value
        //  | AVG_ROW_LENGTH [=] value
        //  | [DEFAULT] CHARACTER SET [=] charset_name
        //  | CHECKSUM [=] {0 | 1}
        //  | [DEFAULT] COLLATE [=] collation_name
        //  | COMMENT [=] 'string'
        //  | COMPRESSION [=] {'ZLIB' | 'LZ4' | 'NONE'}
        //  | CONNECTION [=] 'connect_string'
        //  | {DATA | INDEX} DIRECTORY [=] 'absolute path to directory'
        //  | DELAY_KEY_WRITE [=] {0 | 1}
        //  | ENCRYPTION [=] {'Y' | 'N'}
        //  | ENGINE [=] engine_name
        //  | ENGINE_ATTRIBUTE [=] 'string'
        //  | INSERT_METHOD [=] { NO | FIRST | LAST }
        //  | KEY_BLOCK_SIZE [=] value
        //  | MAX_ROWS [=] value
        //  | MIN_ROWS [=] value
        //  | PACK_KEYS [=] {0 | 1 | DEFAULT}
        //  | PASSWORD [=] 'string'
        //  | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}
        //  | START TRANSACTION
        //  | SECONDARY_ENGINE_ATTRIBUTE [=] 'string'
        //  | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}
        //  | STATS_PERSISTENT [=] {DEFAULT | 0 | 1}
        //  | STATS_SAMPLE_PAGES [=] value
        //  | tablespace_option
        //  | UNION [=] (tbl_name[,tbl_name]...)
        //}

        PartitionOptions partitionOptions = new PartitionOptions();

        Map<String, String> tblOptionMap = new HashMap<>();
        boolean startTransaction = false;

        String tablespaceName = "";
        String storage = "";
        while (wordListScanner.haveNext()) {
            String current = wordListScanner.current();
            String pre = wordListScanner.getPreWord();
            String prepre = wordListScanner.getPrePreWord();
            String next = wordListScanner.getNextWord();
            String nextnext = wordListScanner.getNextNextWord();
            String _key = "";
            String _val = "";

            //  | [DEFAULT] CHARACTER SET [=] charset_name
            //   | [DEFAULT] COLLATE [=] collation_name
            //   | {DATA | INDEX} DIRECTORY [=] 'absolute path to directory'
            //    | START TRANSACTION
            switch (current) {
                case "start":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        if (ParseUtil.isWord(next, "TRANSACTION")) {
                            startTransaction = true;
                        }
                    }
                    break;
                case "character":
                    break;
                case "set":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        if (ParseUtil.isWord(pre, "character")) {
                            _key = "CHARACTER SET";
                            if (ParseUtil.isWord(next, "=")) {
                                wordListScanner.next();// now is =
                            }
                            wordListScanner.next(); // now is the val
                            _val = wordListScanner.current();
                            // 单引号要单独处理
                            if (ParseUtil.isWord(_val, "'")) {
                                _val = wordListScanner.findMatchSamePair("'");
                            }
                            tblOptionMap.put(_key, _val);
                            break;
                        }
                    }
                    break;
                case "collate":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        _key = current;
                        if (ParseUtil.isWord(next, "=")) {
                            wordListScanner.next();// now is =
                        }
                        wordListScanner.next(); // now is the val
                        _val = wordListScanner.current();
                        // 单引号要单独处理
                        if (ParseUtil.isWord(_val, "'")) {
                            _val = wordListScanner.findMatchSamePair("'");
                        }
                        tblOptionMap.put(_key, _val);
                    }
                    break;
                case "data":
                    break;
                case "index":
                    break;
                case "directory":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        _key = current;
                        final boolean preIsIndex = ParseUtil.isWord(pre, "index");
                        if (ParseUtil.isWord(next, "=")) {
                            wordListScanner.next();// now is =
                        }
                        wordListScanner.next(); // now is the val
                        _val = wordListScanner.current();
                        // 单引号要单独处理
                        if (ParseUtil.isWord(_val, "'")) {
                            _val = wordListScanner.findMatchSamePair("'");
                        }
                        if (preIsIndex) {
                            tblOptionMap.put("index directory", _val);
                        } else {
                            tblOptionMap.put(_key, _val);
                        }
                    }
                    break;
                case "autoextend_size":
                case "auto_increment":
                case "avg_row_length":
                case "checksum":
                case "comment":
                case "compression":
                case "connection":
                case "delay_key_write":
                case "encryption":
                case "engine":
                case "engine_attribute":
                case "insert_method":
                case "key_block_size":
                case "max_rows":
                case "min_rows":
                case "pack_keys":
                case "password":
                case "row_format":
                case "secondary_engine_attribute":
                case "stats_auto_recalc":
                case "stats_persistent":
                case "stats_sample_pages":
                case "charset":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        _key = current;
                        if (ParseUtil.isWord(next, "=")) {
                            wordListScanner.next();// now is =
                        }
                        wordListScanner.next(); // now is the val
                        _val = wordListScanner.current();
                        if (ParseUtil.isWord(_val, "'")) {
                            _val = wordListScanner.findMatchSamePair("'");
                        }
                        tblOptionMap.put(_key, _val);
                    }
                    break;
                case "tablespace":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        wordListScanner.next(); // now is tablespace_name
                        tablespaceName = wordListScanner.current();
                    }
                    break;
                case "storage":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        wordListScanner.next(); // now is storage
                        storage = wordListScanner.current();
                    }
                    break;
                case "disk":
                    storage = "disk";
                    break;
                case "memory":
                    storage = "memory";
                    break;
                case "union":
                    if (_main_step == CreateDefinitionTypeEnum.table_options) {
                        if (ParseUtil.isWord(next, "=")) {
                            wordListScanner.next();// now is =
                        }
                        wordListScanner.next(); // now is the val
                        // now is (
                        if (!ParseUtil.isWord(wordListScanner.current(), "(")) {
                            throw new RuntimeException("table_option 语法错误 union 后面需要是(tbl_name,tbl_name....)");
                        }
                        String unionTableList = wordListScanner.findMatchDiffPair("(", ")");
                        tblOptionMap.put("union", unionTableList);
                    }
                    break;
                case "partition":
                    _main_step = CreateDefinitionTypeEnum.partition_options;
                    StringBuilder sb = new StringBuilder();
                    while (wordListScanner.haveNext()) {
                        String _curr_word = wordListScanner.current();
                        sb.append(_curr_word).append(" ");
                        wordListScanner.next(); // move to next one
                    }
                    // 当前元素没有下一个了 处理下当前元素
                    sb.append(wordListScanner.current()).append(" ");
                    if (sb.length() > 0) {
                        partitionOptions.setPartitionBy(sb.toString());
                    }
                    break;
//                case "by":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " by");
//                    }
//                    break;
//                case "linear":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        if (partitionOptions.getPartitionBy() == null) {
//                            partitionOptions.setPartitionBy("linear ");
//                        } else {
//                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " linear ");
//                        }
//                    }
//                    break;
//                case "hash":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        wordListScanner.next(); // skip hash now is (
//                        String _hash_expr = wordListScanner.
//                                findMatchDiffPair("(", ")");
//                        partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + "hash(" + _hash_expr + ") ");
//                    }
//                    break;
//                case "key":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " key ");
//                        wordListScanner.next(); // skip key
//                        if (ParseUtil.isWord(wordListScanner.current(), "algorithm")) {
//                            wordListScanner.next();
//                            if (ParseUtil.isWord(wordListScanner.current(), "=")) {
//                                wordListScanner.next(); // skip =
//                            }
//                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + "ALGORITHM=" + wordListScanner.current() + " ");
//                            wordListScanner.next(); // skip ALGORITHM
//                            if (ParseUtil.isWord(wordListScanner.current(), "(")) {
//                                String _key_column_list = wordListScanner.findMatchDiffPair("(", ")");
//                                partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + "(" + _key_column_list + ") ");
//                            }
//                        } else if (ParseUtil.isWord(wordListScanner.current(), "(")) {
//                            String _key_column_list = wordListScanner.findMatchDiffPair("(", ")");
//                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + "(" + _key_column_list + ") ");
//                        } else {
//                            throw new RuntimeException("PARTITION BY 解析key的expr报错");
//                        }
//                    }
//                    break;
//                case "range":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        wordListScanner.next();
//                        String _range_expr = wordListScanner.findMatchDiffPair("(", ")");
//                        partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " range(" + _range_expr + ") ");
//                        if (ParseUtil.isWord(wordListScanner.getNextWord(), "COLUMNS")) {
//                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy());
//                            wordListScanner.next(); // skip ) now is COLUMNS
//                            wordListScanner.next(); // skip COLUMNS now is (
//                            String _column_list = wordListScanner.findMatchDiffPair("(", ")");
//                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " COLUMNS(" + _column_list + ") ");
//                        }
//                    }
//                    break;
//                case "list":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                            wordListScanner.next();
//                            String _range_expr = wordListScanner.findMatchDiffPair("(", ")");
//                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " list(" + _range_expr + ") ");
//                            if (ParseUtil.isWord(wordListScanner.getNextWord(), "COLUMNS")) {
//                                partitionOptions.setPartitionBy(partitionOptions.getPartitionBy());
//                                wordListScanner.next(); // skip ) now is COLUMNS
//                                wordListScanner.next(); // skip COLUMNS now is (
//                                String _column_list = wordListScanner.findMatchDiffPair("(", ")");
//                                partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " COLUMNS(" + _column_list + ") ");
//                            }
//                        }
//                    }
//                    break;
//                case "algorithm":
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                    }
//                    break;
//                case "subpartition":
//                    _main_step = CreateDefinitionTypeEnum.partition_options;
//                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
//                        partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " subpartition");
//                    }
//                    break;
                default:
                    if (_main_step == CreateDefinitionTypeEnum.partition_options) {
                        // 剩下的 partition_options 不解析了
                        // 直接读到语句结束
                        sb = new StringBuilder();
                        while (wordListScanner.haveNext()) {
                            String _curr_word = wordListScanner.current();
                            sb.append(_curr_word).append(" ");
                            wordListScanner.next(); // move to next one
                        }
                        sb.append(wordListScanner.current()).append(" ");
                        if (sb.length() > 0) {
                            partitionOptions.setPartitionBy(partitionOptions.getPartitionBy() + " " + sb.toString());
                        }
                    }
                    break;
            }
            wordListScanner.next();
        }

        if (startTransaction) {
            tblOptionMap.put("START TRANSACTION", String.valueOf(startTransaction));
        }
        TableOption tableOption = new TableOption();
        tableOption.setTblOptionMap(tblOptionMap);
        tableOption.setStorage(storage);
        tableOption.setTablespaceName(tablespaceName);

        ddl.setTableOption(tableOption);


        ddl.setPartitionOptions(partitionOptions);

        return ddl;
    }

    private List<List<String>> getCreateDefinitionList() {

        List<List<String>> res = new ArrayList<>();
        Stack<String> stack01 = new Stack<>();
        String w = this.wordListScanner.current();
        if (!StringUtils.equalsIgnoreCase("(", w)) {
            throw new RuntimeException("create_definition 解析阶段失败 没有以(开始 " + this.wordListScanner.debug());
        }
        stack01.push("(");
        this.wordListScanner.next();
        List<String> sub = new ArrayList<>();
        while (this.wordListScanner.haveWord() && stack01.isEmpty() == false) {
            w = this.wordListScanner.current();
            sub.add(w);
            switch (w) {
                case "(":
                    stack01.push("(");
                    break;
                case ")":
                    stack01.pop();
                    break;
                case ",":
                    String pre = this.wordListScanner.getPreWord();
                    String next = this.wordListScanner.getNextWord();
                    if (StringUtils.equalsIgnoreCase(pre, "'") &&
                            StringUtils.equalsIgnoreCase(next, "'")) {
                        break;
                    } else {
                        // 这里要处理列里面本身就有逗号 一个明显的例子就是外键有类似
                        // (id,id2,id3) 这样的数组 这里需要甄别一下
                        // (sdfjisdfij,sdfji(id1,
                        // (sdfjisdfij,sdfji(id1,id2) sdfdf(id,id2
                        if (stack01.size() % 2 == 0) {
                            // 说明还在解析中 没有到末尾的逗号
                        } else {
                            res.add(sub); // 遇到逗号了 说明单行结束了
                            sub = new ArrayList<>();
                        }
                        break;
                    }
                default:
                    break;
            }
            this.wordListScanner.next();
        }
        return res;
    }

    private DdlTable step01TableName() {

        // CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
        DdlTable ddlTable = new DdlTable();
        boolean end = false;
        START:
        while (this.wordListScanner.haveWord() && end == false) {
            String current = this.wordListScanner.current();
            switch (current) {
                case "create":
                    break;
                case "temporary":
                    ddlTable.setTemporary(true);
                    break;
                case "table":
                    break;
                case "if":
                case "not":
                case "exists":
                    ddlTable.setIfNotExist(true);
                    break;
                default:
                    // 这里就是tbl_name了
                    String pre = this.wordListScanner.getPreWord();
                    if (StringUtils.equalsIgnoreCase(pre, "TABLE") || StringUtils.equalsIgnoreCase(pre, "EXISTS")) {
                        ddlTable.setTableName(current);
                        end = true;
                        this.wordListScanner.next(); // 结束了
                        continue START;
                    }
                    throw new RuntimeException("没有解析到正确的tbl_name " + this.wordListScanner.debug());
            }
            this.wordListScanner.next();
        }
        return ddlTable;
    }

}

